﻿using LxBasic;
using System;

namespace LxLESS
{
    public class MGJointCreator
    {
        public MGTemp.CellToStoreFace[] coarseOBouFaces;

        IBuildMGJoint fineJoint;

        (int OFlag, int NFlag)[] JointFlags;

        MGJoint coarseJoint;
        public MGJoint CreateMGJoint(IBuildMGJoint fineJoint, MGZone OZone, IndexRange OIndex, MGZone NZone, IndexRange NIndex)
        {
            this.fineJoint = fineJoint;

            coarseJoint = new MGJoint()
            {
                O_Zone = OZone,
                N_Zone = NZone,
                O_BouIndex = OIndex,
                N_BouIndex = NIndex,
            };
            initialize();
            makeFlag();
            addJointFaceToStorage();
            splitJointCoarseFaceFromStorage();
            return coarseJoint;
        }
        protected void initialize()
        {
            JointFlags = new (int OFlag, int NFlag)[fineJoint.GetFaceIdx().GetCount()];
            for (int i1 = 0; i1 < JointFlags.Length; i1++)
            {
                JointFlags[i1] = (-1, -1);
            }
        }
        private void makeFlag()
        {
            {
                (int i1, int end) = coarseJoint.O_BouIndex.Get();
                var bouFaces = coarseJoint.O_Zone.BouFaces;
                for (; i1 < end; i1++)
                {
                    foreach (var side in bouFaces[i1].FineSides)
                    {
                        foreach (var j in fineJoint.GetOZoneSideJoints(side))
                        {
                            JointFlags[j].OFlag = i1;
                        }
                    }
                }
            }
            {
                (int i1, int end) = coarseJoint.N_BouIndex.Get();
                var bouFaces = coarseJoint.N_Zone.BouFaces;
                for (; i1 < end; i1++)
                {
                    foreach (var side in bouFaces[i1].FineSides)
                    {
                        foreach (var j in fineJoint.GetNZoneSideJoints(side))
                        {
                            JointFlags[j].NFlag = i1;
                        }
                    }
                }
            }
        }
        private void addJointFaceToStorage()
        {
            coarseOBouFaces = new MGTemp.CellToStoreFace[coarseJoint.O_BouIndex.GetCount()];
            for (int i0 = 0; i0 < coarseOBouFaces.Length; i0++)
            {
                coarseOBouFaces[i0] = new();
            }
            int AllMinus = coarseJoint.O_BouIndex.Start;
            for (int i1 = 0; i1 < JointFlags.Length; i1++)
            {
                add();
                void add()
                {
                    var flag = JointFlags[i1];
                    var store = coarseOBouFaces[flag.OFlag - AllMinus].CoarseOFaces;
                    foreach (var f in store)
                    {
                        if (f.NSideCell == flag.NFlag)
                        {
                            f.FineFace_O2N.Add(i1);
                            return;
                        }
                    }
                    MGTemp.Face cfnew = new()
                    {
                        OSideCell = flag.OFlag,
                        NSideCell = flag.NFlag,
                    };
                    cfnew.FineFace_O2N.Add(i1);
                    store.Add(cfnew);
                }
            }
        }
        private void splitJointCoarseFaceFromStorage()
        {
            int icount = 0;
            foreach (var c in coarseOBouFaces)
            {
                icount += c.CoarseOFaces.Count;
            }
            MGJoiFace[] Joints = new MGJoiFace[icount];
            var O_BouFaces = coarseJoint.O_Zone.BouFaces;
            var N_BouFaces = coarseJoint.N_Zone.BouFaces;
            {
                int i1 = 0;
                foreach (var c in coarseOBouFaces)
                {
                    foreach (var f in c.CoarseOFaces)
                    {
                        Joints[i1] = new MGJoiFace()
                        {
                            FineJoints = f.FineFace_O2N.ToArray(),
                            O_BouFace = f.OSideCell,
                            O_InnCell = O_BouFaces[f.OSideCell].OSideCell,
                            N_BouFace = f.NSideCell,
                            N_InnCell = N_BouFaces[f.NSideCell].OSideCell,
                        };
                        i1++;
                    }
                }
            }
            {
                (int oStart, int oEnd) = coarseJoint.O_BouIndex.Get();
                (int nStart, int nEnd) = coarseJoint.N_BouIndex.Get();
                AssignJointToBoundTool astool = new(coarseJoint.O_BouIndex.GetCount(), coarseJoint.N_BouIndex.GetCount(), icount);
                for (int i1 = 0; i1 < Joints.Length; i1++)
                {
                    ref var j = ref Joints[i1];
                    astool.AssignJointToSide(j.O_BouFace - oStart, j.N_BouFace - nStart, i1);
                }
                for (int i1 = oStart; i1 < oEnd; i1++)
                {
                    O_BouFaces[i1].Joints = astool.GetOBouFJoints(i1 - oStart);
                }
                for (int i1 = nStart; i1 < nEnd; i1++)
                {
                    N_BouFaces[i1].Joints = astool.GetNBouFJoints(i1 - nStart);
                }
            }
            coarseJoint.JoiFaces = Joints;
        }
    }
}